#include "city.h"
#include "map.h"
#include "clock.h"
#include "tile.h"
#include "buildable.h"
#include "residential.h"
#include "commercial.h"
#include "industrial.h"
#include "power/power-line.hpp"
#include "road.h"

//////////////////////////////////////////////////
//  City::City()
//////////////////////////////////////////////////
City::City() :
    cityName("New City"),
    mayorName("Your Name"),
    money(100000),
    population(0),
    map(NULL),
    clock(NULL)
{
    // Create a map
    map = new Map(128, 128);
    clock = new Clock(this);
}

//////////////////////////////////////////////////
//  void City::eventHandle(sf::Event event)
//////////////////////////////////////////////////
void City::eventHandle(sf::Event event)
{
    if (event.type == sf::Event::KeyPressed)
    {
        if (event.key.code == sf::Keyboard::Equal)
        {
            clock->increaseSpeed();
        }
        else if (event.key.code == sf::Keyboard::Dash)
        {
            clock->decreaseSpeed();
        }
    }
}

//////////////////////////////////////////////////
//  void City::inputHandle()
//////////////////////////////////////////////////
void City::inputHandle()
{

}

//////////////////////////////////////////////////
//  void City::Update(double dt)
//////////////////////////////////////////////////
void City::update(double dt)
{
    map->update(dt);
    clock->update(dt);
}

//////////////////////////////////////////////////
//  void City::tick()
//////////////////////////////////////////////////
void City::tick()
{
    map->tick();
}

//////////////////////////////////////////////////////////////
//  void City::place()
//////////////////////////////////////////////////////////////
void City::place(Buildable::Type type, Buildable::Density density, sf::Vector2i tileCoords)
{
    Tile* tile = map->getTile(tileCoords);

    if (tile)
    {
        if (tile->getChild() != NULL) // The tile already contains an object
        {
            destroy(tileCoords);
        }

        Buildable* obj = createBuildable(type, density, tileCoords);

        if (obj) {
            tile->setChild(obj);
            obj->onPlace();

            subtractMoney(obj->getCost());
        }
    }
}

//////////////////////////////////////////////////////////////
//  void City::build(sf::Vector2i tileCoords)
//////////////////////////////////////////////////////////////
void City::build(sf::Vector2i tileCoords)
{
    Tile* tile = map->getTile(tileCoords);

    if (tile)
    {
        Buildable* obj = tile->getChild();

        if (obj)
        {
            obj->onBuild();
        }
    }
}

//////////////////////////////////////////////////////////////
//  void City::destroy(sf::Vector2i tileCoords)
//////////////////////////////////////////////////////////////
void City::destroy(sf::Vector2i tileCoords)
{
    Tile* tile = map->getTile(tileCoords);

    if (tile)
    {
        Buildable* obj = tile->getChild();

        if (obj)
        {
            obj->onDestroy();

            // Remove object from lists
            switch (obj->getType())
            {
                case Buildable::RESIDENTIAL:
                {
                    obj = new Residential;
                    residentialBuildings.remove(static_cast<Residential*>(obj));
                    break;
                }
                case Buildable::COMMERCIAL:
                {
                    obj = new Commercial;
                    commercialBuildings.remove(static_cast<Commercial*>(obj));
                    break;
                }
                case Buildable::INDUSTRIAL:
                {
                    obj = new Industrial;
                    industrialBuildings.remove(static_cast<Industrial*>(obj));
                    break;
                }
                case Buildable::ROAD:
                {
                    obj = new Road;
                    roads.remove(static_cast<Road*>(obj));
                    break;
                }
                case Buildable::RAIL:
                {
                    break;
                }
                case Buildable::POWER_LINE:
                {
                    break;
                }
                case Buildable::POWER_PLANT:
                {
                    break;
                }
                case Buildable::CIVIC:
                {
                    break;
                }
            }

            BuildableList::const_iterator it = std::find_if(buildables.cbegin(), buildables.cend(),
                                                            [obj](const std::unique_ptr<Buildable>& other) {
                                                              return other.get() == obj;
                                                            });
            if (it != buildables.end())
            {
                buildables.erase(it);
            }

            tile->setChild(NULL);
        }
    }
}

//////////////////////////////////////////////////////////////
//  void City::createBuildable()
//////////////////////////////////////////////////////////////
Buildable* City::createBuildable(Buildable::Type type, Buildable::Density density, sf::Vector2i tileCoords)
{
    Buildable* obj = NULL;

    switch (type)
    {
        case Buildable::RESIDENTIAL:
        {
            obj = new Residential;
            residentialBuildings.push_back(static_cast<Residential*>(obj));
            break;
        }
        case Buildable::COMMERCIAL:
        {
            obj = new Commercial;
            commercialBuildings.push_back(static_cast<Commercial*>(obj));
            break;
        }
        case Buildable::INDUSTRIAL:
        {
            obj = new Industrial;
            industrialBuildings.push_back(static_cast<Industrial*>(obj));
            break;
        }
        case Buildable::ROAD:
        {
            obj = new Road;
            roads.push_back(static_cast<Road*>(obj));
            break;
        }
        case Buildable::RAIL:
        {
            break;
        }
        case Buildable::POWER_LINE:
        {
            obj = new PowerLine;
            break;
        }
        case Buildable::POWER_PLANT:
        {
            break;
        }
        case Buildable::CIVIC:
        {
            break;
        }
        default:
        {
            printf("Tried to add an unkown object type! Make sure object has been added to Buildable::Type");
            break;
        }
    }

    if (obj)
    {
        buildables.push_back(std::unique_ptr<Buildable>(obj));
        obj->setDensity(density);
        obj->setOrigin(tileCoords);
    }

    return obj;
}
